/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.support.scripting.cmd;

import cn.easyplatform.EasyPlatformWithLabelKeyException;
import cn.easyplatform.FieldNotFoundException;
import cn.easyplatform.ScriptEvalExitException;
import cn.easyplatform.ScriptRuntimeException;
import cn.easyplatform.contexts.ListContext;
import cn.easyplatform.contexts.RecordContext;
import cn.easyplatform.contexts.WorkflowContext;
import cn.easyplatform.dos.FieldDo;
import cn.easyplatform.dos.Record;
import cn.easyplatform.entities.beans.table.TableBean;
import cn.easyplatform.entities.helper.EventLogic;
import cn.easyplatform.lang.Nums;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.support.scripting.*;
import cn.easyplatform.support.sql.SqlParser;
import cn.easyplatform.type.ScopeType;
import cn.easyplatform.util.RuntimeUtils;
import org.mozilla.javascript.IdScriptableObject;
import org.mozilla.javascript.Wrapper;

import java.math.BigDecimal;
import java.util.*;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class ListCmd extends AbstractScriptCmd {

    private ListContext lc;

    private WorkflowContext ctx;

    private RecordContext target;

    private RecordContext source;

    /**
     * @param ctx
     */
    public ListCmd(WorkflowContext ctx, ListContext lc, ScriptCmdContext cr) {
        super(cr);
        this.lc = lc;
        this.ctx = ctx;
        this.source = cr.getSource();
        this.target = cr.getTarget();
    }

    public void setValue(String name, Object value) {
        setValue(name, value, '$', "");
    }

    public void setValue(String name, Object value, char c) {
        setValue(name, value, c, "");
    }

    public void setValue(String name, Object value, char c, String type) {
        if (c == '@' && source == null)
            throw new FieldNotFoundException("entity.table.variable.not.found",
                    name);
        value = RuntimeUtils.castTo(value);
        if (name.compareTo("700") >= 0 && name.compareTo("899") < 0) {
            if (c == '$')
                target.setParameter(name, value);
            else
                source.setParameter(name, value);
        } else {
            FieldDo fd = null;
            if (c == '$')
                fd = target.getField(name);
            else
                fd = source.getField(name);
            if (type.equals("") || type.equals("value"))
                fd.setValue(value);
            else {
                if (type.equals("name"))
                    fd.setName(value == null ? "" : value.toString());
                else if (type.equals("len"))
                    fd.setLength(Nums.toInt(value, 0));
                else if (type.equals("decimal"))
                    fd.setDecimal(Nums.toInt(value, 0));
                else if (type.equals("scope"))
                    fd.setScope(ScopeType.valueOf(value.toString()));
                else if (type.equals("acc"))
                    fd.setAcc(value == null ? "" : value.toString());
                else if (type.equals("mode"))
                    fd.setShareModel(Nums.toInt(value, 0));
                else if (type.equals("$") || type.equals("@")) {
                    if (fd.getValue() != null)
                        setValue(fd.getValue().toString(), value, c, "");
                }
            }
        }
    }

    public Object getValue(String name) {
        return getValue(name, '$', "");
    }

    public Object getValue(String name, char c) {
        return getValue(name, c, "");
    }

    public Object getValue(String name, char c, String type) {
        if (c == '@' && source == null)
            throw new FieldNotFoundException("entity.table.variable.not.found",
                    name);
        if (name.compareTo("700") >= 0 && name.compareTo("899") < 0) {
            if (c == '$')
                return target.getParameter(name);
            else
                return source.getParameter(name);
        }
        FieldDo fd = null;
        if (c == '$')
            fd = target.getField(name);
        else
            fd = source.getField(name);
        if (type.equals("value") || type.equals(""))
            return fd.getValue();
        else if (type.equals("type"))
            return fd.getType().toString();
        else if (type.equals("name"))
            return fd.getName();
        else if (type.equals("len"))
            return fd.getLength();
        else if (type.equals("decimal"))
            return fd.getDecimal();
        else if (type.equals("scope"))
            return fd.getScope().toString();
        else if (type.equals("acc"))
            return fd.getAcc();
        else if (type.equals("mode"))
            return fd.getShareModel();
        else if (type.equals("empty")) {
            return fd.isEmpty();
        } else if (type.equals("length")) {
            if (fd.getValue() instanceof Object[]) {
                return ((Object[]) fd.getValue()).length;
            } else
                return fd.getValue() == null ? 0 : String
                        .valueOf(fd.getValue()).length();
        } else if (type.equals("$") || type.equals("@")) {// 获取值中值
            if (fd.getValue() != null)
                return getValue(fd.getValue().toString(), c, "");
            return null;
        } else
            return fd.getValue();
    }

    public RecordContext create() {
        RecordContext rc = null;
        if (!Strings.isBlank(lc.getBean().getTable())) {
            TableBean tb = scc.getCommandContext().getEntity(
                    lc.getBean().getTable());
            Record record = RuntimeUtils.createRecord(scc.getCommandContext(),
                    tb, tb.isAutoKey());
            rc = lc.createRecord(record);
        } else
            rc = lc.createRecord((Object[]) null);
        rc.setParameter("814", 'C');
        rc.setParameter("815", true);
        if (!Strings.isBlank(lc.getBeforeLogic())) {
            RecordContext[] rcs = {scc.getTarget(), rc};
            String code = RuntimeUtils.eval(scc.getCommandContext(),
                    lc.getBeforeLogic(), rcs);
            if (!code.equals("0000"))
                throw new ScriptRuntimeException(code, scc.getCommandContext()
                        .getMessage(code, target));
        }
        lc.appendRecord(rc, false);
        lc.setFromInit(true);
        return rc;
    }

    public boolean remove(RecordContext rc) {
        return lc.getRecords().remove(rc);
    }

    public void init(int num, String expr) {
        if (num > 0) {
            CompliableScriptEngine compiler1 = null;
            CompliableScriptEngine compiler2 = null;
            ScriptCmdContext cx = (ScriptCmdContext) scc.getScope().get("$");
            RhinoScriptable scope = cx.getScope();
            if (!Strings.isBlank(lc.getBeforeLogic())) {
                EventLogic el = RuntimeUtils.castTo(scc.getCommandContext(),
                        scc.getTarget(), lc.getBeforeLogic());
                if (el != null)
                    compiler1 = ScriptEngineFactory.createCompilableEngine(scc,
                            el.getContent(), scope);
            }
            if (!Strings.isBlank(expr)) {
                EventLogic el = RuntimeUtils.castTo(scc.getCommandContext(),
                        scc.getTarget(), expr);
                if (el != null)
                    compiler2 = ScriptEngineFactory.createCompilableEngine(scc,
                            el.getContent(), scope);
            }
            TableBean tb = scc.getCommandContext().getEntity(
                    lc.getBean().getTable());
            int rowIndex = 1;
            RecordContext tmp1 = cx.getSource();
            RecordContext tmp2 = cx.getTarget();
            try {
                for (int i = 0; i < num; i++) {
                    lc.setParameter("857", rowIndex);
                    Record record = RuntimeUtils.createRecord(
                            cx.getCommandContext(), tb, tb.isAutoKey());
                    rowIndex++;
                    RecordContext rc = lc.createRecord(record);
                    this.target = rc;
                    this.source = scc.getTarget();
                    cx.setSource(this.source);
                    cx.setTarget(this.target);
                    if (compiler1 != null) {
                        cx.setScope(compiler1.getScope());
                        compiler1.eval();
                    }
                    if (compiler2 != null) {
                        cx.setScope(compiler2.getScope());
                        compiler2.eval();
                    }
                    lc.appendRecord(rc, false);
                    cx.setSource(tmp1);
                    cx.setTarget(tmp2);
                }
            } catch (ScriptEvalExitException ex) {
                throw new ScriptRuntimeException(ex.getMessage(), scc
                        .getCommandContext().getMessage(ex.getMessage(),
                                ex.getRecord()));
            } finally {
                if (compiler1 != null)
                    compiler1.destroy();
                if (compiler2 != null)
                    compiler2.destroy();
                cx.setSource(tmp1);
                cx.setTarget(tmp2);
                cx.setScope(scope);
            }
            lc.setFromInit(true);
        }
    }

    /**
     * @param fields
     */
    public void append(FieldDo[] fields) {
        Record record = new Record();
        for (FieldDo field : fields)
            record.set(field);
        RecordContext rc = lc.createRecord(record);
        lc.appendRecord(rc, true);
    }

    /**
     * 从数据库加载数据
     *
     * @param sql
     * @param expr
     */
    public void load(String sql, String expr) {
        SqlParser<FieldDo> sp = RuntimeUtils.createSqlParser(FieldDo.class);
        sql = sp.parse(sql, scc.getScope(), scc.getSource(), scc.getTarget());
        List<FieldDo[]> data = scc.getCommandContext().getBizDao()
                .selectList(sql, sp.getParams());
        if (!data.isEmpty()) {
            String code = lc.getParameterAsString("814");
            TableBean tb = scc.getCommandContext().getEntity(
                    lc.getBean().getTable());
            CompliableScriptEngine compiler1 = null;
            CompliableScriptEngine compiler2 = null;
            ScriptCmdContext cx = (ScriptCmdContext) scc.getScope().get("$");
            RhinoScriptable scope = cx.getScope();
            if (!Strings.isBlank(lc.getBeforeLogic())) {
                EventLogic el = RuntimeUtils.castTo(scc.getCommandContext(),
                        scc.getTarget(), lc.getBeforeLogic());
                if (el != null)
                    compiler1 = ScriptEngineFactory.createCompilableEngine(scc,
                            el.getContent(), scope);
            }
            if (!Strings.isBlank(expr)) {
                EventLogic el = RuntimeUtils.castTo(scc.getCommandContext(),
                        scc.getTarget(), expr);
                if (el != null)
                    compiler2 = ScriptEngineFactory.createCompilableEngine(scc,
                            el.getContent(), scope);
            }
            RecordContext rc = null;
            RecordContext tmp1 = cx.getSource();
            RecordContext tmp2 = cx.getTarget();
            try {
                lc.setParameter("856", data.size());
                int rowIndex = 1;
                int failedCount = 0;
                for (FieldDo[] fields : data) {
                    lc.setParameter("857", rowIndex);
                    Record record = RuntimeUtils.createRecord(
                            scc.getCommandContext(), tb,
                            tb.isAutoKey() && code.equals("C"));
                    if (compiler2 == null) {
                        Set<String> columnNames = record.getColumnNames();
                        for (FieldDo fd : fields) {
                            if (columnNames.contains(fd.getName()))
                                record.get(fd.getName())
                                        .setValue(fd.getValue());
                        }
                    }
                    rowIndex++;
                    rc = lc.createRecord(record);
                    if (compiler1 != null) {
                        this.target = rc;
                        this.source = scc.getTarget();
                        cx.setSource(this.source);
                        cx.setTarget(this.target);
                        cx.setScope(compiler1.getScope());
                        compiler1.eval();
                    }
                    try {
                        if (compiler2 != null) {
                            Record source = new Record();
                            for (FieldDo fd : fields)
                                source.set(fd);
                            RecordContext src = rc.clone();
                            src.setData(source);
                            this.target = rc;
                            this.source = src;
                            cx.setSource(this.source);
                            cx.setTarget(this.target);
                            cx.setScope(compiler2.getScope());
                            compiler2.eval();
                        }
                    } catch (ScriptEvalExitException ex) {
                        failedCount++;
                        rc.setParameter("858", failedCount);
                        if (!target.getParameterAsBoolean("855")) // 如果855不为真，则直接退出
                            throw new ScriptRuntimeException(ex.getMessage(),
                                    scc.getCommandContext().getMessage(
                                            ex.getMessage(), ex.getRecord()));
                        continue;
                    } finally {
                        cx.setSource(tmp1);
                        cx.setTarget(tmp2);
                    }
                    lc.appendRecord(rc, false);
                }
            } finally {
                if (compiler1 != null)
                    compiler1.destroy();
                if (compiler2 != null)
                    compiler2.destroy();
                cx.setSource(tmp1);
                cx.setTarget(tmp2);
                cx.setScope(scope);
            }
        }
        lc.setFromInit(true);
    }

    /**
     * 从父层功能的列表中获取记录
     *
     * @param listId
     * @param expr
     */
    public int from$(String listId, String expr) {
        return from$(listId, expr, true);
    }

    /**
     * 从父层功能的列表中获取记录
     *
     * @param listId
     * @param expr
     * @param sel
     */
    public int from$(String listId, String expr, boolean sel) {
        ListContext sc = null;
        if (ctx.getParentId() != null) {
            WorkflowContext cx = scc.getCommandContext().getWorkflowContext(
                    ctx.getParentId());
            if (cx == null)
                throw new EasyPlatformWithLabelKeyException(
                        "task.parent.not.found", ctx.getParentId());
            sc = cx.getList(listId);
        } else
            sc = scc.getWorkflowContext().getList(listId);
        if (sc == null)
            throw new EasyPlatformWithLabelKeyException("datalist.not.found",
                    listId);
        return transfer(sc, lc, expr, sel);
    }

    /**
     * 当前列表到父功能列表
     *
     * @param listId
     * @param expr
     * @return
     */
    public int to$(String listId, String expr) {
        return to$(listId, expr, true);
    }

    /**
     * 当前列表到父功能列表
     *
     * @param listId
     * @param expr
     * @param selected
     * @return
     */
    public int to$(String listId, String expr, boolean selected) {
        ListContext sc = null;
        if (ctx.getParentId() != null) {
            WorkflowContext cx = scc.getCommandContext().getWorkflowContext(
                    ctx.getParentId());
            if (cx == null)
                throw new EasyPlatformWithLabelKeyException(
                        "task.parent.not.found", ctx.getParentId());
            sc = cx.getList(listId);
        }
        if (sc == null)
            throw new EasyPlatformWithLabelKeyException("datalist.not.found",
                    listId);
        return transfer(lc, sc, expr, selected);
    }

    private int transfer(ListContext sourceList, ListContext targetList,
                         String expr, boolean sel) {
        CompliableScriptEngine compiler1 = null;
        CompliableScriptEngine compiler2 = null;
        ScriptCmdContext cx = (ScriptCmdContext) scc.getScope().get("$");
        RhinoScriptable scope = cx.getScope();
        if (!Strings.isBlank(targetList.getBeforeLogic())) {
            EventLogic el = RuntimeUtils.castTo(scc.getCommandContext(),
                    scc.getTarget(), targetList.getBeforeLogic());
            if (el != null)
                compiler1 = ScriptEngineFactory.createCompilableEngine(scc,
                        el.getContent(), scope);
        }
        if (!Strings.isBlank(expr)) {
            EventLogic el = RuntimeUtils.castTo(scc.getCommandContext(),
                    scc.getTarget(), expr);
            if (el != null)
                compiler2 = ScriptEngineFactory.createCompilableEngine(scc,
                        el.getContent(), scope);
        }
        TableBean tb = scc.getCommandContext().getEntity(
                targetList.getBean().getTable());
        int rowIndex = 0;
        RecordContext tmp1 = cx.getSource();
        RecordContext tmp2 = cx.getTarget();
        try {
            for (RecordContext sourcec : sourceList.getRecords()) {
                if (sourcec.getParameterAsChar("814") != 'D') {
                    if (sel && !sourcec.getParameterAsBoolean("853"))// 选择
                        continue;
                    rowIndex++;
                    targetList.setParameter("857", rowIndex);
                    Record record = RuntimeUtils.createRecord(
                            scc.getCommandContext(), tb, tb.isAutoKey());
                    RecordContext rc = targetList.createRecord(record);
                    this.target = rc;
                    this.source = sourcec;
                    cx.setSource(this.source);
                    cx.setTarget(this.target);
                    if (compiler1 != null) {
                        cx.setScope(compiler1.getScope());
                        compiler1.eval();
                    }
                    if (compiler2 != null) {
                        try {
                            cx.setScope(compiler2.getScope());
                            compiler2.eval();
                        } catch (ScriptEvalExitException ex) {
                            // 可以对列表已存在的记录进行判断
                            if (!rc.getParameterAsBoolean("855"))// 如果855不为真，则直接退出
                                throw new ScriptRuntimeException(
                                        ex.getMessage(), scc
                                        .getCommandContext()
                                        .getMessage(ex.getMessage(),
                                                ex.getRecord()));
                        }
                    }
                    targetList.appendRecord(rc, false);
                    cx.setSource(tmp1);
                    cx.setTarget(tmp2);
                }
            }
            lc.setFromInit(true);
            return rowIndex;
        } finally {
            if (compiler1 != null)
                compiler1.destroy();
            if (compiler2 != null)
                compiler2.destroy();
            cx.setSource(tmp1);
            cx.setTarget(tmp2);
            cx.setScope(scope);
        }
    }

    /**
     * 从指定层、指定的子任务id和列表id获取数据
     *
     * @param layer
     * @param taskId
     * @param listId
     * @param expr
     */
    public void load(int layer, String taskId, String listId, String expr) {
        String id = ctx.getTask(layer, taskId);
        if (id == null)
            throw new EasyPlatformWithLabelKeyException(
                    "task.not.found.from.layer", layer, taskId);
        WorkflowContext ctx = scc.getCommandContext().getWorkflowContext(id);
        if (ctx == null)
            throw new EasyPlatformWithLabelKeyException(
                    "task.not.found.from.layer", layer, taskId);
        ListContext lc = ctx.getList(listId);
        if (lc == null)
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.not.found.from.task", layer, taskId, listId);
        load(lc, expr);
    }

    /**
     * 从其它层的列表加载数据
     *
     * @param layer
     * @param listId
     * @param expr
     */
    public void load(int layer, String listId, String expr) {
        ListContext lc = ctx.getList(layer, listId);
        if (lc == null)
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.not.found.from.layer", layer, listId);
        load(lc, expr);
    }

    public void setParameter(String name, Object value) {
        lc.setParameter(name, value);
    }

    public Object getParameter(String name) {
        return lc.getParameter(name);
    }

    public int getTotalSize() {
        return lc.getTotalSize();
    }

    public double sum(String name) {
        if (lc.getRecords().isEmpty())
            return 0d;
        BigDecimal sum = new BigDecimal(0);
        for (RecordContext rc : lc.getRecords()) {
            if (rc.getParameterAsChar("814") != 'D') {
                Object v = rc.getFieldValue(name);
                if (v != null) {
                    BigDecimal bd = new BigDecimal(v.toString());
                    sum = sum.add(bd);
                }
            }
        }
        return sum.doubleValue();
    }

    public void clear(int type) {
        lc.clear(type);
        for (ListContext c : ctx.getLists()) {
            if (c.getId().equals(lc.getHost()))
                c.clear(2);
        }
    }

    public double sum(String name, String expression) {
        if (lc.getRecords().isEmpty())
            return 0d;
        if (Strings.isBlank(expression))
            return sum(name);
        EventLogic el = RuntimeUtils.castTo(scc.getCommandContext(),
                scc.getTarget(), expression);
        CompliableScriptEngine engine = ScriptEngineFactory
                .createCompilableEngine(scc.getCommandContext(),
                        el.getContent());
        BigDecimal sum = new BigDecimal(0);
        for (RecordContext rc : lc.getRecords()) {
            if (rc.getParameterAsChar("814") != 'D') {
                Object o = engine.eval(rc);
                if (o instanceof Boolean && (Boolean) o) {
                    Object v = rc.getFieldValue(name);
                    if (v != null) {
                        BigDecimal bd = new BigDecimal(v.toString());
                        sum = sum.add(bd);
                    }
                }
            }
        }
        return sum.doubleValue();
    }

    public void applyAll(String name, Object value) {
        for (RecordContext rc : lc.getRecords()) {
            if (rc.getParameterAsChar("814") != 'D') {
                rc.setValue(name, value);
                if (rc.getParameterAsChar("814") == 'R') {
                    rc.setParameter("814", "U");
                    rc.setParameter("815", true);
                }
            }
        }
    }

    public RecordContext getRecord(int index) {
        return lc.getRecords().get(index);
    }

    public RecordContext[] getSelectedData() {
        List<RecordContext> records = new ArrayList<RecordContext>();
        for (RecordContext rc : lc.getRecords()) {
            if (rc.getParameterAsChar("814") != 'D'
                    && rc.getParameterAsBoolean("853"))
                records.add(rc);
        }
        if (records.isEmpty())
            return new RecordContext[0];
        RecordContext[] ar = new RecordContext[records.size()];
        records.toArray(ar);
        return ar;
    }

    public RecordContext[] getData() {
        List<RecordContext> records = new ArrayList<RecordContext>();
        for (RecordContext rc : lc.getRecords())
            records.add(rc);
        if (records.isEmpty())
            return new RecordContext[0];
        RecordContext[] ar = new RecordContext[records.size()];
        records.toArray(ar);
        return ar;
    }

    public List<Map<String, Object>> toMapList() {
        return lc.toMapList(0, false);
    }

    public List<Map<String, Object>> toSelectedMapList() {
        return lc.toMapList(0, true);
    }

    public int getCount() {
        return lc.getRecords().size();
    }

    public int getSelectedCount() {
        int count = 0;
        for (RecordContext rc : lc.getRecords()) {
            if (rc.getParameterAsChar("814") != 'D'
                    && rc.getParameterAsBoolean("853"))
                count++;
        }
        return count;
    }

    public void setHostValue(String name, Object value) {
        if (Strings.isBlank(lc.getHost()))
            ctx.getRecord().setValue(name, value);
        else {
            for (ListContext c : ctx.getLists()) {
                if (c.getId().equals(lc.getHost())) {
                    RecordContext rc = c.getRecord(lc.getHostKey());
                    if (rc == null)
                        throw new EasyPlatformWithLabelKeyException(
                                "context.datalist.record.not.found",
                                lc.getId(), lc.getHostKey());
                    rc.setValue(name, value);
                    if (rc.getParameterAsChar("814") == 'R') {
                        rc.setParameter("814", "U");
                        rc.setParameter("815", true);
                    }
                    break;
                }
            }
        }
    }

    public Object getHostValue(String name) {
        if (Strings.isBlank(lc.getHost()))
            return ctx.getRecord().getValue(name);
        for (ListContext c : ctx.getLists()) {
            if (c.getId().equals(lc.getHost())) {
                RecordContext rc = lc.getRecord(lc.getHostKey());
                if (rc == null)
                    if (rc == null)
                        throw new EasyPlatformWithLabelKeyException(
                                "context.datalist.record.not.found",
                                lc.getId(), lc.getHostKey());
                return rc.getValue(name);
            }
        }
        return null;
    }

    public void sort(final String sortBy, final String sortTarget,
                     final boolean isAscending) {
        List<RecordContext> records = lc.getRecords();
        if (records != null && !records.isEmpty()) {
            List<RecordContext> rcs = new ArrayList<RecordContext>(records);
            Collections.sort(rcs, new Comparator<RecordContext>() {
                @SuppressWarnings("unchecked")
                @Override
                public int compare(RecordContext o1, RecordContext o2) {
                    Comparable<Object> c1 = (Comparable<Object>) o1
                            .getValue(sortBy);
                    Comparable<Object> c2 = (Comparable<Object>) o2
                            .getValue(sortBy);
                    if (isAscending) {
                        if (c2 != null && c1 != null)
                            return c2.compareTo(c1);
                        else if (c2 != null)
                            return 1;
                        else if (c1 != null)
                            return -1;
                        else
                            return 0;
                    } else {
                        if (c1 != null && c2 != null)
                            return c1.compareTo(c2);
                        else if (c1 != null)
                            return 1;
                        else if (c2 != null)
                            return -1;
                        else
                            return 0;
                    }
                }

            });
            int count = records.size();
            for (int i = 0; i < count; i++) {
                if (isAscending)
                    rcs.get(i).setValue(sortTarget, i + 1);
                else
                    rcs.get(i).setValue(sortTarget, count - i);
            }
        }
    }

    private void load(ListContext lc, String expr) {
        List<RecordContext> records = lc.getRecords();
        if (records != null && !records.isEmpty()) {
            String code = lc.getParameterAsString("814");
            TableBean tb = scc.getCommandContext().getEntity(
                    lc.getBean().getTable());
            CompliableScriptEngine compiler1 = null;
            CompliableScriptEngine compiler2 = null;
            ScriptCmdContext cx = (ScriptCmdContext) scc.getScope().get("$");
            RhinoScriptable scope = cx.getScope();
            if (!Strings.isBlank(lc.getBeforeLogic())) {
                EventLogic el = RuntimeUtils.castTo(scc.getCommandContext(),
                        scc.getTarget(), lc.getBeforeLogic());
                if (el != null)
                    compiler1 = ScriptEngineFactory.createCompilableEngine(scc,
                            el.getContent(), scope);
            }
            if (!Strings.isBlank(expr)) {
                EventLogic el = RuntimeUtils.castTo(scc.getCommandContext(),
                        scc.getTarget(), expr);
                if (el != null)
                    compiler2 = ScriptEngineFactory.createCompilableEngine(scc,
                            el.getContent(), scope);
            }
            RecordContext rc = null;
            RecordContext tmp1 = cx.getSource();
            RecordContext tmp2 = cx.getTarget();
            try {
                lc.setParameter("856", records.size());
                int rowIndex = 1;
                int failedCount = 0;
                for (RecordContext fields : records) {
                    lc.setParameter("857", rowIndex);
                    Record record = RuntimeUtils.createRecord(
                            scc.getCommandContext(), tb,
                            tb.isAutoKey() && code.equals("C"));
                    if (compiler2 == null) {
                        Set<String> columnNames = record.getColumnNames();
                        for (FieldDo fd : fields.getRecordFieldValues()) {
                            if (columnNames.contains(fd.getName()))
                                record.get(fd.getName())
                                        .setValue(fd.getValue());
                        }
                    }
                    rowIndex++;
                    rc = lc.createRecord(record);
                    if (compiler1 != null) {
                        this.target = rc;
                        this.source = scc.getTarget();
                        cx.setSource(this.source);
                        cx.setTarget(this.target);
                        cx.setScope(compiler1.getScope());
                        compiler1.eval();
                    }
                    try {
                        if (compiler2 != null) {
                            this.target = rc;
                            this.source = fields;
                            cx.setSource(this.source);
                            cx.setTarget(this.target);
                            cx.setScope(compiler2.getScope());
                            compiler2.eval();
                        }
                    } catch (ScriptEvalExitException ex) {
                        failedCount++;
                        target.setParameter("858", failedCount);
                        if (!target.getParameterAsBoolean("855"))// 如果855不为真，则直接退出
                            throw new ScriptRuntimeException(ex.getMessage(),
                                    scc.getCommandContext().getMessage(
                                            ex.getMessage(), ex.getRecord()));
                        continue;
                    } finally {
                        cx.setSource(tmp1);
                        cx.setTarget(tmp2);
                    }
                    lc.appendRecord(rc, false);
                }
                lc.setFromInit(true);
            } finally {
                if (compiler1 != null)
                    compiler1.destroy();
                if (compiler2 != null)
                    compiler2.destroy();
                cx.setSource(tmp1);
                cx.setTarget(tmp2);
                cx.setScope(scope);
            }
        }
    }
}
